using System;
using System.Linq.Expressions;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace N3P.WCF.Proxyless.FullDuplex.Silverlight
{
    /// <summary>
    /// Proxy class for handling calls to a full duplex WCF service
    /// </summary>
    /// <typeparam name="TService">The service contract with synchronous methods</typeparam>
    /// <typeparam name="TCallback">The type of the callback contract</typeparam>
    public class WcfClient<TService, TCallback> : WcfClientBase
        where TCallback : class
    {

        /// <summary>
        /// Creates a new instance of the <see cref="WcfClient{TService, TCallback}"/>
        /// </summary>
        /// <param name="responder">The instance of the callback contract for the service that should have its members invoked appropriate to the calls sent from the server</param>
        /// <param name="endpointConfigurationName">The name of the endpoint configuration to use</param>
        /// <param name="endpointAddress">The location the service should be accessed from</param>
        public WcfClient(TCallback responder, string endpointConfigurationName, string endpointAddress)
            : base(typeof(TService), responder, endpointConfigurationName, endpointAddress)
        {
        }

        /// <summary>
        /// Creates a new instance of the <see cref="WcfClient{TService, TCallback}"/>
        /// </summary>
        /// <param name="responder">The instance of the callback contract for the service that should have its members invoked appropriate to the calls sent from the server</param>
        /// <param name="endpointConfigurationName">The name of the endpoint configuration to use</param>
        /// <param name="endpointAddress">The location the service should be accessed from</param>
        public WcfClient(TCallback responder, string endpointConfigurationName, EndpointAddress endpointAddress)
            : base(typeof(TService), responder, endpointConfigurationName, endpointAddress)
        {
        }

        /// <summary>
        /// Creates a new instance of the <see cref="WcfClient{TService, TCallback}"/>
        /// </summary>
        /// <param name="responder">The instance of the callback contract for the service that should have its members invoked appropriate to the calls sent from the server</param>
        /// <param name="binding">The binding to use</param>
        /// <param name="endpointAddress">The location the service should be accessed from</param>
        public WcfClient(TCallback responder, Binding binding, EndpointAddress endpointAddress)
            : base(typeof(TService), responder, binding, endpointAddress)
        {
        }

        /// <summary>
        /// Creates a new instance of the <see cref="WcfClient{TService, TCallback}"/>
        /// </summary>
        /// <param name="responder">The instance of the callback contract for the service that should have its members invoked appropriate to the calls sent from the server</param>
        /// <param name="endpointConfigurationName">The name of the endpoint configuration to use</param>
        public WcfClient(TCallback responder, string endpointConfigurationName)
            : base(typeof(TService), responder, endpointConfigurationName)
        {
        }

        /// <summary>
        /// Creates a new instance of the <see cref="WcfClient{TService, TCallback}"/>
        /// </summary>
        /// <param name="responder">The instance of the callback contract for the service that should have its members invoked appropriate to the calls sent from the server</param>
        public WcfClient(TCallback responder)
            : base(typeof(TService), responder)
        {
        }




        /// <summary>
        /// Calls a method on the service
        /// </summary>
        /// <param name="call">The call to make</param>
        /// <example>client.Call(service => service.DoSomething());</example>
        public void Call(Expression<Action<TService>> call)
        {
            var message = MessageHelper.PrepareMessage(call, MessageVersion);
            Send(message);
        }
    }
}